package com.listeningframework.boot.codegen.generators.coders;

import com.listeningframework.boot.codegen.constants.Templates;
import com.listeningframework.boot.codegen.context.MetaContext;
import com.listeningframework.boot.codegen.context.MetaData;
import com.listeningframework.boot.codegen.exception.BusinessException;
import com.listeningframework.boot.codegen.lang.CodeGenStringUtils;
import org.apache.commons.collections.CollectionUtils;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

/**
 * 
 * @description Mapper Coder
 *
 * @author lixining
 * @version $Id: MapperCoder.java, v 0.1 2016年12月5日 下午1:53:37 lixining Exp $
 */
public class MapperCoder extends AbstractCoder {
    /**
     * 特殊字段不遍历添加到更新条件
     */
    private static final List<String> SPECIAL_FIELDS = Arrays.asList("CREATED_BY", "UPDATED_BY", "CREATED_DATE",
        "UPDATED_DATE");

    public MapperCoder(MetaContext context) {
        super(context);
    }

    @Override
    protected String getContent() throws BusinessException {
        return render(Templates.MAPPER);
    }

    @Override
    protected Map<String, Object> getParams() {
        Map<String, Object> paramMap = newHashMap();
        paramMap.put("queryCondition", getQueryCondition());
        paramMap.put("insert", getInsert());
        paramMap.put("select", getSelect());
        paramMap.put("count", getCount());
        paramMap.put("selectByPK", getSelectByPK());
        paramMap.put("update", getUpdate());
        paramMap.put("updateAll", getUpdateAll());
        paramMap.put("delete", getDelete());
        return paramMap;
    }

    @Override
    protected String getSavePath() throws BusinessException {
        return context.getMapperPath();
    }

    /**
     * 动态查询条件
     */
    private String getQueryCondition() {
        // @formatter:off
        List<MetaData> metaDataList = context.getEntityMetaList();
        if (CollectionUtils.isEmpty(metaDataList)) {
            return "";
        }
        StringBuilder builder = new StringBuilder();
        builder.append("    <sql id=\"QueryConditionSql\">").append("\n");
        builder.append("        <where>").append("\n");
        for (MetaData meta : metaDataList) {
            if (meta.isDateType()) {
                continue;
            }
            String javaName = meta.getJavaName();
            String columnName = meta.getColumnName();
            String columnType = meta.getColumnType();
            String condition = meta.getMapperCondition();
            builder.append("            <if test=\">")
                   .append(condition)
                   .append("\">").append("\n");
            builder.append("                AND ")
                   .append(columnName).append("= ")
                   .append("#{").append(javaName)
                   .append(", jdbcType=")
                   .append(columnType)
                   .append("}")
                   .append("\n");
            builder.append("            </if>").append("\n");
        }
        builder.append("        </where>").append("\n");
        builder.append("    </sql>").append("\n");
        return builder.toString();
        // @formatter:on
    }

    /**
     * Insert语句
     */
    private String getInsert() {
        // @formatter:off
        List<MetaData> metaDataList = context.getEntityMetaList();
        if (CollectionUtils.isEmpty(metaDataList)) {
            return "";
        }
        StringBuilder fields = new StringBuilder();
        StringBuilder values = new StringBuilder();
        int index = 0;
        for (MetaData meta : metaDataList) {
            index++;
            if (meta.isKey() || meta.isDateType() || SPECIAL_FIELDS.contains(meta.getColumnName())) {
                continue;
            }
            String columnName = meta.getColumnName();
            fields.append("            ").append(columnName);
            values.append("            ").append("#{")
                  .append(columnName)
                  .append(", jdbcType=")
                  .append(meta.getColumnType())
                  .append("}");
            if (index != metaDataList.size() - 1) {
                fields.append(",");
                values.append(",");
            }
            fields.append("\n");
            values.append("\n");
        }
        
        StringBuilder builder = new StringBuilder();
        builder.append("        INSERT INTO ")
               .append(context.getTableName()).append("\n")
               .append("(").append("\n")
               .append(fields.toString())
               .append(") VALUES (").append("\n")
               .append(values.toString())
               .append(")");
        
        return builder.toString();
        // @formatter:on
    }

    /**
     * 查询语句
     */
    private String getSelect() {
        List<MetaData> metaDataList = context.getEntityMetaList();
        if (CollectionUtils.isEmpty(metaDataList)) {
            return "";
        }
        StringBuilder builder = new StringBuilder();
        builder.append("            SELECT ");
        int index = 0;
        for (MetaData meta : metaDataList) {
            index++;
            String columnName = meta.getColumnName();
            String padColumnName = CodeGenStringUtils.rpad(columnName, 20, " ");
            String javaName = meta.getJavaName().toUpperCase();
            builder.append("                   ").append(padColumnName).append(" ").append(javaName);
            if (index != metaDataList.size() - 1) {
                builder.append(",");
            }
        }
        builder.append("            FROM ").append(context.getTableName());
        return builder.toString();
    }

    /**
     * Count语句
     */
    private String getCount() {
        List<MetaData> metaDataList = context.getEntityMetaList();
        if (CollectionUtils.isEmpty(metaDataList)) {
            return "";
        }
        StringBuilder builder = new StringBuilder();
        builder.append("            SELECT COUNT(1) FROM ").append(context.getTableName());
        return builder.toString();
    }

    /**
     * 主键查询语句
     */
    private String getSelectByPK() {
        List<MetaData> metaDataList = context.getEntityMetaList();
        if (CollectionUtils.isEmpty(metaDataList)) {
            return "";
        }
        StringBuilder builder = new StringBuilder(getSelect());
        builder.append("             WHERE ID = #{VALUE}");
        return builder.toString();
    }

    /**
     * 删除语句
     */
    private String getDelete() {
        StringBuilder builder = new StringBuilder();
        builder.append("            DELETE FROM ").append(context.getTableName()).append(" WHERE ID = #{VALUE}");
        return builder.toString();
    }

    /**
     * 条件更新语句
     */
    private String getUpdate() {
        // @formatter:off
        List<MetaData> metaDataList = context.getEntityMetaList();
        if (CollectionUtils.isEmpty(metaDataList)) {
            return "";
        }
        StringBuilder builder = new StringBuilder();
        builder.append("        <![CDATA[").append("\n");
        builder.append("            ").append("UPDATE ").append(context.getTableName()).append("\n");
        builder.append("        ]]>").append("\n");
        builder.append("        <set>").append("\n");
        builder.append("            UPDATED_BY   = #{updatedBy, jdbcType=VARCHAR}, ").append("\n");
        builder.append("            UPDATED_DATE = CURRENT_TIMESTAMP,").append("\n");

        for (MetaData meta : metaDataList) {
            if (meta.isDateType() || meta.isKey() || SPECIAL_FIELDS.contains(meta.getColumnName())) {
                continue;
            }
            String javaName = meta.getJavaName();
            String columnName = meta.getColumnName();
            String columnType = meta.getColumnType();
            String condition = meta.getMapperCondition();
            builder.append("            <if test=\">")
                   .append(condition)
                   .append("\">").append("\n");
            builder.append("                ")
                   .append(columnName)
                   .append(" = ")
                   .append("#{")
                   .append(javaName)
                   .append(", jdbcType=").append(columnType).append("}").append(",")
                   .append("\n");
            builder.append("            </if>").append("\n");
        }

        builder.append("        </set>");
        builder.append("        <![CDATA[");
        builder.append("            WHERE ID = #{id, jdbcType=BIGINT}");
        builder.append("        ]]>");
        return builder.toString();
        // @formatter:on
    }

    /**
     * 全部更新语句
     */
    private String getUpdateAll() {
        // @formatter:off
        List<MetaData> metaDataList = context.getEntityMetaList();
        if (CollectionUtils.isEmpty(metaDataList)) {
            return "";
        }
        StringBuilder builder = new StringBuilder();
        builder.append("            ").append("UPDATE ").append(context.getTableName()).append("\n");
        builder.append("            SET UPDATED_BY   = #{updatedBy, jdbcType=VARCHAR},").append("\n");
        builder.append("                UPDATED_DATE = CURRENT_TIMESTAMP,").append("\n");

        for (MetaData meta : metaDataList) {
            if (meta.isDateType() || meta.isKey() || SPECIAL_FIELDS.contains(meta.getColumnName())) {
                continue;
            }
            String javaName = meta.getJavaName();
            String columnName = meta.getColumnName();
            String columnType = meta.getColumnType();
            builder.append("                ")
                   .append(columnName)
                   .append(" = ")
                   .append("#{")
                   .append(javaName)
                   .append(", jdbcType=").append(columnType).append("}").append(",")
                   .append("\n");
        }

        builder.append("            WHERE ID = #{id, jdbcType=BIGINT}").append("\n");
        return builder.toString();
        // @formatter:on
    }

}
